﻿using Utility3D.Extensions;
using System.Linq;

namespace Utility3D
{
    public class DrawingSurface : IModelObject
    {
        public DrawingSurface(WorldModel worldModel, string name, Plane plane, double height, double width)
        {
            WorldModel = worldModel;
            Name = name;
            Plane = plane;
            Height = height;
            Width = width;

            Transient = true;
        }

        public void DiscardSurface()
        {
            if (PrevSurface != null)
                PrevSurface.NextSurface = NextSurface;
            if (NextSurface != null)
                NextSurface.PrevSurface = PrevSurface;
        }

        public DrawingSurface Glide(double depth)
        {
            if (DistanceFromBaseSurface != 0.0)
            {
                var baseSurface = this.ChainWithSelf(s => s.PrevSurface).FirstOrDefault(s => s.DistanceFromBaseSurface == 0.0) ??
                                  this.ChainWithSelf(s => s.NextSurface).First(s => s.DistanceFromBaseSurface == 0.0);

                return baseSurface.Glide(depth + DistanceFromBaseSurface);
            }


            var basePointOffset = Plane.Normal*-depth;
            var newPlane = new Plane(Plane.BasePoint + basePointOffset, Plane.VectorX, Plane.VectorY);
            var newSurface = new DrawingSurface(WorldModel, Name + " " + depth, newPlane, Height, Width)
                                 {DistanceFromBaseSurface = depth};

            if (depth >= 0)
            {
                var nextSurface = this.ChainWithSelf(s => s.NextSurface).FirstOrDefault(s => s.DistanceFromBaseSurface >= depth);
                if (nextSurface != null)
                {
                    if (nextSurface.DistanceFromBaseSurface == depth) return nextSurface;
                    newSurface.NextSurface = nextSurface;
                    newSurface.PrevSurface = nextSurface.PrevSurface;
                    if (newSurface.PrevSurface != null)
                        newSurface.PrevSurface.NextSurface = newSurface;
                    nextSurface.PrevSurface = newSurface;
                    return newSurface;
                }

                var prevSurface = this.ChainWithSelf(s => s.NextSurface).Last();
                newSurface.PrevSurface = prevSurface;
                prevSurface.NextSurface = newSurface;
                return newSurface;
            }
            else
            {
                var prevSurface = this.ChainWithSelf(s => s.PrevSurface).FirstOrDefault(s => s.DistanceFromBaseSurface <= depth);
                if (prevSurface != null)
                {
                    if (prevSurface.DistanceFromBaseSurface == depth) return prevSurface;
                    newSurface.PrevSurface = prevSurface;
                    newSurface.NextSurface = prevSurface.NextSurface;
                    if (newSurface.NextSurface != null)
                        newSurface.NextSurface.PrevSurface = newSurface;
                    prevSurface.NextSurface = newSurface;
                    return newSurface;
                }

                var nextSurface = this.ChainWithSelf(s => s.PrevSurface).Last();
                newSurface.NextSurface = nextSurface;
                nextSurface.PrevSurface = newSurface;
                return newSurface;
            }
        }


        [ExcludeFromPersistence]
        public bool Transient { get; private set; }
        public double DistanceFromBaseSurface { get; private set; }
        public DrawingSurface NextSurface { get; private set; }
        public DrawingSurface PrevSurface { get; private set; }

        public WorldModel WorldModel { get; private set; }
        public string Name { get; private set; }
        public Plane Plane { get; private set; }
        public double Height { get; private set; }
        public double Width { get; private set; }

        private int _id;
        public int Id
        {
            get { return _id; }
// ReSharper disable UnusedMember.Local
            private set
            {
                Transient = false;
                _id = value;
            }
// ReSharper restore UnusedMember.Local
        }
    }
}